package com.alinesno.cloud.common.web.base.controller;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.lang.reflect.ParameterizedType;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.builder.ToStringBuilder;
import org.apache.poi.ss.usermodel.Workbook;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.domain.Page;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.http.HttpStatus;
import org.springframework.ui.Model;
import org.springframework.util.Assert;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;

import com.alinesno.cloud.base.boot.entity.ManagerAccountEntity;
import com.alinesno.cloud.common.facade.orm.entity.BaseEntity;
import com.alinesno.cloud.common.facade.pageable.DatatablesPageBean;
import com.alinesno.cloud.common.facade.response.ResponseBean;
import com.alinesno.cloud.common.facade.response.ResponseGenerator;
import com.alinesno.cloud.common.facade.services.IBaseService;
import com.alinesno.cloud.common.facade.wrapper.RestWrapper;
import com.alinesno.cloud.common.web.login.aop.AccountRecord;
import com.alinesno.cloud.common.web.login.aop.AccountRecord.RecordType;
import com.alinesno.cloud.common.web.login.aop.DataFilter;
import com.alinesno.cloud.common.web.login.session.CurrentAccountSession;
import com.fasterxml.jackson.databind.ObjectMapper;

import cn.afterturn.easypoi.excel.ExcelExportUtil;
import cn.afterturn.easypoi.excel.entity.ExportParams;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.bean.copier.CopyOptions;

/**
 * 基础操作层
 * @author WeiXiaoJin
 * @since 2018年12月23日 下午12:21:42
 */
public abstract class FeignMethodController<DTO extends BaseEntity , FEIGN extends IBaseService<DTO, String>> extends BaseController {

	protected CopyOptions copyOptions = new CopyOptions().setIgnoreNullValue(true) ; 

	private static final Logger log = LoggerFactory.getLogger(FeignMethodController.class) ; 
	protected ObjectMapper objectMapper = new ObjectMapper();  

	// 文件共享路径 
	@Value("${alinesno.share.path:/tmp/}")
	private String sharePath ; 
	
//	@Autowired
//	@Autowired
//	protected FEIGN feign ; 

	/**
	 * 解决Dubbo无法识别泛型的问题
	 * @return
	 */
	public abstract FEIGN getFeign() ; 

	/**
	 * 填充用户权限
	 * @param bean
	 */
	protected void fillOperator(BaseEntity bean) {
		ManagerAccountEntity account = CurrentAccountSession.get(request) ; 
		bean.setOperatorId(account.getId()) ; //CurrentAccountSession.get(request).getId());
		bean.setDepartmentId(account.getDepartmentId());
	}

	/**
	 * 查询所有，数据过滤
	 * @param feign
	 * @param applicationId
	 * @return
	 */
	protected List<DTO> findAll(FEIGN feign , String applicationId) {
		ManagerAccountEntity account = CurrentAccountSession.get(request) ;
		if(StringUtils.isBlank(applicationId)) {
			applicationId = account.getApplicationId() ; 
		}
		RestWrapper restWrapper = new RestWrapper().eq("applicationId", applicationId) ; 
		
		List<DTO> list = feign.findAll(restWrapper) ; 
		return list ; 
	}

	protected DatatablesPageBean toPage(Model model, FEIGN feign , DatatablesPageBean page, RestWrapper wrapper , Page<DTO> pageableResult) {
	
		RestWrapper restWrapper = page.buildWrapper(page, wrapper) ; 
		
		if(pageableResult == null) {
			pageableResult = feign.findAllByWrapperAndPageable(restWrapper) ; 
		}
		
		if(page.isBootstrapTable()) {
			// ----------------------- 兼容bootstrap table_start ---------------
			page.setRows(pageableResult.getContent());
			page.setTotal((int) pageableResult.getTotalElements());
			page.setCode(HttpStatus.OK.value()); 
			// ----------------------- 兼容bootstrap table_end ---------------
		} else {
			page.setData(pageableResult.getContent());
			page.setDraw(page.getDraw());
			page.setRecordsFiltered((int) pageableResult.getTotalElements());
			page.setRecordsTotal((int) pageableResult.getTotalElements());
		}
		
		return page ;
	}
	
	protected DatatablesPageBean toPage(Model model, FEIGN feign , DatatablesPageBean page, RestWrapper wrapper) {
		return toPage(model, feign, page, wrapper , null) ;  
	}
	
	protected DatatablesPageBean toPage(Model model, FEIGN feign, DatatablesPageBean page) {
		return toPage(model, feign, page, null) ; 
	}
	
	@GetMapping("/list")
    public void list(){
    }

	/**
	 * 菜单管理查询功能  
	 * @return
	 */
//	@RequiresPermissions("sys:user:save")
	@AccountRecord(type=RecordType.ACCESS_ADD)
	@GetMapping("/add")
    public void add(Model model , HttpServletRequest request){
    }
	
	
	/**
	 * 保存新对象 
	 * @param model
	 * @param ManagerCodeEntity
	 * @return
	 */
	@AccountRecord(type=RecordType.OPERATE_SAVE)
	// @FormToken(save=true)
	@ResponseBody
	@PostMapping("/save")
	public ResponseBean save(Model model , HttpServletRequest request, DTO dto) {
		log.debug("===> save dto:{}" , ToStringBuilder.reflectionToString(dto));
		
		dto.setOperatorId(CurrentAccountSession.get(request).getId());
		dto.setDepartmentId(CurrentAccountSession.get(request).getDepartmentId());
		
		dto = getFeign().save(dto) ; 
		return ResponseGenerator.ok(null) ; 	
	}
	
	
	/**
	 * 删除
	 */
//	@AccountRecord(type=RecordType.OPERATE_DELETE)
//	@ResponseBody
//	@PostMapping("/delete")
//    public ResponseBean delete(@RequestParam(value = "rowsId[]") String[] rowsId){
//		log.debug("rowsId = {}" , ToStringBuilder.reflectionToString(rowsId));
//		if(rowsId != null && rowsId.length > 0) {
//			getFeign().deleteByIds(rowsId); 
//		}
//		return ResponseGenerator.ok(null) ; 
//    }
	
	/**
	 * 删除
	 */
	@AccountRecord(type=RecordType.OPERATE_DELETE)
	@ResponseBody
	@GetMapping("/delete")
    public ResponseBean delete(String ids){
		log.debug("delete ids:{}" , ids);
		
		String[] rowsId = ids.split(",") ; 
		if (rowsId != null && rowsId.length > 0) {
			getFeign().deleteByIds(rowsId);
		}
		return ResponseGenerator.ok(null);
    }
	

	/**
	 * 详情
	 */
	@AccountRecord(type=RecordType.OPERATE_QUERY)
	@ResponseBody
	@GetMapping("/detailJson")
    public ResponseBean detail(String id){
		log.debug("id = {}" , id);
		DTO bean = getFeign().findEntityById(id) ; 
		return bean != null?ResponseGenerator.ok(bean):ResponseGenerator.fail("") ; 
    }

	/**
	 * 保存
	 * @param model
	 * @param request
	 * @param ManagerApplicationEntity
	 * @return
	 */
	@AccountRecord(type=RecordType.OPERATE_UPDATE)
	// @FormToken(remove=true)
	@ResponseBody
	@PostMapping("/update")
	public ResponseBean update(Model model , HttpServletRequest request, DTO dto) {
		
		if(dto != null && StringUtils.isNotBlank(dto.getId())) {
			
			DTO oldBean = getFeign().getOne(dto.getId()) ; 
			BeanUtil.copyProperties(dto, oldBean ,CopyOptions.create().setIgnoreNullValue(true));
			
			oldBean.setLastUpdateOperatorId(CurrentAccountSession.get(request).getId());
			
			oldBean = getFeign().save(oldBean) ; 
			return ResponseGenerator.ok(null) ; 	
			
		}else {
			return this.save(model, request, dto) ; 
		}
	}

	/**
	 * 查询所有
	 * @param applicationId
	 * @return
	 */
	@ResponseBody
	@GetMapping("findAll")
	public List<DTO> findAll(){
		return getFeign().findAll() ; 
	}

	/**
	 * 查询返回实体
	 * @param applicationId
	 * @return
	 */
	@ResponseBody
	@GetMapping("getOne")
	public DTO getOne(@RequestParam("id") String id) {
		return getFeign().getOne(id) ; 
	}

	/**
	 * 查询统计 
	 * @param applicationId
	 * @return
	 */
	@ResponseBody
	@GetMapping("count")
	public long count() {
		return getFeign().count() ; 
	}
	
	/**
	 * 删除
	 * @param id
	 */
	@ResponseBody
	@GetMapping("deleteById")
	public void deleteById(@RequestParam("id") String id) {
		getFeign().deleteById(id); ; 
	}

	/**
	 * 查询所有通过applicationId
	 * @param applicationId
	 * @return
	 */
	@ResponseBody
	@GetMapping("findAllByApplicationId")
	List<DTO> findAllByApplicationId(@RequestParam("applicationId") String applicationId){
		return getFeign().findAllByTenantId(applicationId) ; 
	}
	
	/**
	 * 查询所有通过applicationId
	 * @param applicationId
	 * @return
	 */
	@ResponseBody
	@GetMapping("findAllByTenantId")
	List<DTO> findAllByTenantId(@RequestParam("tenantId") String tenantId){
		return getFeign().findAllByTenantId(tenantId) ; 
	}


	/**
	 * 修改功能  
	 * @return
	 */
//	@FormToken(save=true)
	@GetMapping("/modify")
    public void modify(HttpServletRequest request ,Model model , String id){
		Assert.hasLength(id , "主键不能为空.");
		DTO code = getFeign().getOne(id) ;
		log.debug("modify bean:{}" , ToStringBuilder.reflectionToString(code));
		model.addAttribute("bean", code) ; 
    }

	/**
	 * 详情
	 * @return
	 */
//	@FormToken(save=true)
	@GetMapping("/detail")
    public void detail(HttpServletRequest request ,Model model , String id){
		Assert.hasLength(id , "主键不能为空.");
		DTO code = getFeign().getOne(id) ; 
		model.addAttribute("bean", code) ; 
    }
	

	/**
	 * 修改状态
	 * @return
	 */
	@ResponseBody
	@GetMapping("/changeStatus")
    public ResponseBean changeStatus(String id){
		boolean b = getFeign().modifyHasStatus(id) ; 
		return ResponseGenerator.ok(b) ; 
    }

	/**
	 * 导出Excel
	 * @param id
	 * @return 
	 * @return
	 * @throws IOException 
	 */
	@DataFilter
	@SuppressWarnings("unchecked")
	@ResponseBody
	@PostMapping("/exportExcel")
    public ResponseBean exportExcel(DatatablesPageBean page , HttpServletResponse response) throws IOException{
		RestWrapper restWrapper = new RestWrapper() ; 
		restWrapper.builderCondition(page.getCondition()) ; 
		
		Specification<DTO> spec = restWrapper.toSpecification();
		List<DTO> list = this.getFeign().findAll(spec);
		log.debug("list:{}" , list);
	
		Class<DTO> tClass = (Class<DTO>)((ParameterizedType)getClass().getGenericSuperclass()).getActualTypeArguments()[0];
		Workbook workbook = ExcelExportUtil.exportExcel(new ExportParams(), tClass ,list);

		
		File f = new File(sharePath) ; 
		if(!f.exists()) {
			f.mkdir(); 
		}
		
		SimpleDateFormat sdf = new SimpleDateFormat("yyyy_MM_dd_HH_mm_ss");
		String path = sdf.format(new Date())+".xls" ;
		
		OutputStream stream = new FileOutputStream(new File(sharePath + File.separator + path));
        workbook.write(stream) ; 
        stream.close();  
        
        return ResponseGenerator.ok(sharePath+path); 
    }
	
	/**
	 * 清空并删除所有 
	 * @param id
	 * @return
	 */
	@DataFilter
	@ResponseBody
	@PostMapping("/cleanAll")
    public ResponseBean cleanAll(DatatablesPageBean page){
		RestWrapper restWrapper = new RestWrapper() ; 
		restWrapper.builderCondition(page.getCondition()) ; 
		
		getFeign().deleteByWrapper(restWrapper);
		return ResponseGenerator.ok(null) ; 
    }
	
}
